<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
</head>
<body>

<script type="text/javascript">
var ws;
var url;
var testdata = {};
var show_individual_results = true;

function format(val) {
	if (val < 1000) {
		return val + "µs";
	} else if (val >= 1000) {
		return val/1000.0 + "ms";
	}
}

function reset_stats() {
	test_data = {};
	
	$("#token").html("");
	$("#status").html("");
	$("#current_connections").html("");
	$("#max_connections").html("");
	$("#total_connections").html("");
	$("#failed_connections").html("");
	
	$("#open_min").html("");
	$("#open_med").html("");
	$("#open_avg").html("");
	$("#open_max").html("");
	
	$("#msg_min").html("");
	$("#msg_med").html("");
	$("#msg_avg").html("");
	$("#msg_max").html("");
	
	$("#close_min").html("");
	$("#close_med").html("");
	$("#close_avg").html("");
	$("#close_max").html("");
	
	$("#results-body").html("");
}

function connect() {
	url = document.getElementById("server_url").value;
	console.log(url);
	
	if ("WebSocket" in window) {
		ws = new WebSocket(url);
	} else if ("MozWebSocket" in window) {
		ws = new MozWebSocket(url);
	} else {
		write_error("This Browser does not support WebSockets.");
		return;
	}
	ws.onopen = function(e) {
		document.getElementById("server_url").disabled = true;
		document.getElementById("toggle_connect").innerHTML = "Disconnect";
	};
	
	ws.onerror = function(e) {
		write_error("Client: An error occured, see console log for more details.");
		console.log(e);
	};
	
	ws.onclose = function(e) {
		document.getElementById("server_url").disabled = false;
		document.getElementById("toggle_connect").innerHTML = "Connect";
		document.getElementById("server_details").innerHTML = "";
	};
	
	ws.onmessage = function(e) {
		//console.log(e);
		
		var data = JSON.parse(e.data);	
		
		console.log(data);
			
		if (data.type == "test_welcome") {
			var o = "";
			o += "<strong>Version:</strong> "+data.version+" ";
			o += "<strong>Ident:</strong> "+data.ident+" ";
			o += "<strong>num_workers:</strong> "+data.num_workers+" ";
			document.getElementById("server_details").innerHTML = o;
		} else if (data.type == "test_start") {
			$("#token").html(data.token);
			$("#status").html("Started");
			reset_stats();
		} else if (data.type == "test_complete") {
			$("#status").html("Completed");
			
			open_min = 0;
			open_median = [];
			open_mean = 0;
			open_max = 0;
			
			msg_min = 0;
			msg_median = [];
			msg_mean = 0;
			msg_max = 0;
			
			close_min = 0;
			close_median = [];
			close_mean = 0;
			close_max = 0;
			
			for (var i in testdata) {
				open = Math.max(Math.round(testdata[i].open-testdata[i].tcp,2),0);
				fail = Math.max(Math.round(testdata[i].fail-testdata[i].tcp,2),0);
				close = Math.max(Math.round(testdata[i].close-testdata[i].close_sent,2),0);
				
				open = Math.max(fail,open);
				
				if (open < open_min || open_min == 0) {
					open_min = open;
				}
				if (close < close_min || close_min == 0) {
					close_min = close;
				}
				
				open_median.push(open);
				close_median.push(close);
				
				open_mean += open;
				close_mean += close;
				
				if (open > open_max) {
					open_max = open;
				}
				if (close > close_max) {
					close_max = close;
				}
				
				for (var j in testdata[i].messages) {
					net = Math.round(testdata[i].messages[j][1]-testdata[i].messages[j][0],2)
					
					if (net < msg_min || msg_min == 0) {
						msg_min = net;
					}
					if (net > msg_max) {
						msg_max = net;
					}
					
					msg_median.push(net);
					msg_mean += net;
				}
			}
			
			open_mean = Math.round(open_mean / open_median.length);
			msg_mean = Math.round(msg_mean / msg_median.length);
			close_mean = Math.round(close_mean / close_median.length);
			
			open_median.sort();
			msg_median.sort();
			close_median.sort();
			
			var half = Math.floor(open_median.length/2);
			
			if (open_median.length % 2) {
				open_median = open_median[half];
				close_median = close_median[half];
			} else {
				open_median = (open_median[half-1]+open_median[half])/2.0;
				close_median = (close_median[half-1]+close_median[half])/2.0;
			}
			
			half = Math.floor(msg_median.length/2);
			
			if (msg_median.length % 2) {
				msg_median = msg_median[half];
			} else {
				msg_median = (msg_median[half-1]+msg_median[half])/2.0;
			}
			
			$("#open_min").html(format(open_min));
			$("#open_med").html(format(open_median));
			$("#open_avg").html(format(open_mean));
			$("#open_max").html(format(open_max));
			
			$("#msg_min").html(format(msg_min));
			$("#msg_med").html(format(msg_median));
			$("#msg_avg").html(format(msg_mean));
			$("#msg_max").html(format(msg_max));
			
			$("#close_min").html(format(close_min));
			$("#close_med").html(format(close_median));
			$("#close_avg").html(format(close_mean));
			$("#close_max").html(format(close_max));
		} else if (data.type == "test_data") {
			
			$("#current_connections").html(data.data.current_connections);
			$("#max_connections").html(data.data.max_connections);
			$("#total_connections").html(data.data.total_connections);
			$("#failed_connections").html(data.data.failed_connections);
			
			if (data.data.connection_data.length > 0) {
				for (var i in data.data.connection_data) {
					foo = data.data.connection_data[i];
					
					testdata[foo.id] = foo;
					
					if (show_individual_results) {
						if ($("#result-"+foo.id).length == 0) {
							$("#result-"+foo.id+" .result").html(data.data.result);
							
							var o = "";
							o += "<tr id='result-"+foo.id+"'>";
							
							o += "<td class='id'>"+foo.id+"</td>";
							o += "<td class='status'>"+foo.status+"</td>";
							o += "<td class='start'>"+foo.start+"</td>";
							o += "<td class='tcp'>"+Math.max(Math.round(foo.tcp-foo.start,2),0)+"µs</td>";
							
							open = Math.max(Math.round(foo.open-foo.tcp,2),0);
							fail = Math.max(Math.round(foo.fail-foo.tcp,2),0);
							close = Math.max(Math.round(foo.close-foo.close_sent,2),0);
							
							if (open == 0) {
								o += "<td class='open'>"+fail+"µs</td>";
							} else {
								o += "<td class='open'>"+open+"µs</td>";
							}
							
							o += "<td class='close_sent'>"+foo.close_sent+"µs</td>";
							o += "<td class='close'>"+close+"µs</td>";
							
							o += "</tr>";
							
							o += document.getElementById("results-body").innerHTML;
							document.getElementById("results-body").innerHTML = o;
						} else {
							
							temp = foo.tcp-foo.start
							
							$("#result-"+foo.id+" .id").html(foo.id);
							$("#result-"+foo.id+" .status").html(foo.status);
							$("#result-"+foo.id+" .start").html(foo.start+"µs");
							$("#result-"+foo.id+" .tcp").html(Math.max(Math.round(foo.tcp-foo.start,2),0)+"µs");
							
							open = Math.max(Math.round(foo.open-foo.tcp,2),0);
							fail = Math.max(Math.round(foo.fail-foo.tcp,2),0);
							close = Math.max(Math.round(foo.close-foo.close_sent,2),0);
							
							if (open == 0) {
								$("#result-"+foo.id+" .open").html(fail+"µs");
							} else {
								$("#result-"+foo.id+" .open").html(open+"µs");
							}
							
							$("#result-"+foo.id+" .close_sent").html(foo.close_sent+"µs");
							$("#result-"+foo.id+" .close").html(close+"µs");
						}
					}
				}
			}
			
			$("#result-"+data.token).addClass(data.data.result);
		} else if (data.type == "error") {
			$("#result-"+data.token+" .status").html("Error");
			$("#messages").html(data.data+"<br />");
		} else {
			console.log(data);
		}
	};
}

function write_error(msg) {
	$("#messages").css("display","block").html(msg);
}

function disconnect() {
	ws.close();
	$("#server_url").attr("disabled","disabled");
	$("#toggle_connect").html("Connect");
}

function toggle_connect() {
	if ($("#server_url").attr("disabled") == "disabled") {
		disconnect();
	} else {
		connect();
	}
}

function send(ind) {
	$("#messages").css("display","none");
	
	if (ws === undefined || ws.readyState != 1) {
		write_error("Websocket is not avaliable for writing");
		return;
	}	
	
	show_individual_results = ind;
	
	ws.send($("#msg").val());
}

</script>

<style>
body,html {
	margin: 0px;
	padding: 0px;
	font-family: Tahoma,Arial,Verdana,sans-serif;
	background-color: #F4F4F4;
}
#server_url {
	width: 200px;
}
h2 {
	font-size: 18px;
	margin: 20px 20px;
}
#controls {
	/*float:right;*/
	background-color: #333;
	color: white;
	font-size: 14px;
	padding: 4px;
}
#msg {
	width: 100%;
	
	box-sizing: border-box;
	-webkit-box-sizing:border-box;
	-moz-box-sizing: border-box;
	-ms-box-sizing: border-box;
	
	display: block;
	height: 5em;
}
#message_input button {
	display: inline-block;
}

#message_input {
	margin: 0px 20px;
}

#results {
	margin: 0px 20px;
}
#results table {
	width: 100%;
	border: 1px solid white;
	color: white;
	border-collapse: collapse;
	border-spacing: 0px;
	margin-top: 10px;
}

#messages {
	display: none;
	margin: 20px;
	padding: 4px;
	color: white;
}

th,td {
	font-weight: normal;
	padding: 6px;
	font-size: 0.8em;
	border: 1px solid white;
}

thead tr {
	background-color: #048;
}

tbody tr {
	background-color: #666;
}
.pass {
	background-color: #0A0;
}
.fail {
	background-color: #900;
}
.error {
	background-color: #9A0;
}

</style>

<div id="controls">
	<div id="server">
		<input type="text" name="server_url" id="server_url" value="ws://localhost:9050" />
		<button id="toggle_connect" onclick="toggle_connect();">Connect</button>
		<span id="server_details"></span>
	</div>
</div>
<h2>Run Test</h2>
<div id="message_input">
	<textarea type="text" id="msg">stress_test:uri=ws://localhost:9002;token=stress;connection_count=5;handshake_delay=10;</textarea><br />
	<button onclick="send(true);">Run Test</button> <button onclick="send(false);">Run Test (aggregate results only)</button>
</div>
<h2>Test Results</h2>
<div id="messages" class='fail'></div>
<div id="results">
	<!--<div>
		Token: <span id="token"></span><br />
		Status: <span id="status">N/A</span><br />
		Current Connections: <span id="current_connections"></span><br />
		Max Connections: <span id="max_connections"></span><br />
		Total Connections: <span id="total_connections"></span><br />
		Failed Connections: <span id="failed_connections"></span><br />
	</div>-->
	<table>
		<thead>
		<tr>
			<th rowspan="2">Token</th>
			<th rowspan="2">Status</th>
			<th colspan="4">Connections</th>
			<th colspan="4">Open</th>
			<th colspan="4">Messages</th>
			<th colspan="4">Close</th>
		</tr>
		<tr>
			<th>Current</th>
			<th>Max</th>
			<th>Total</th>
			<th>Failed</th>
			
			<th>Min</th>
			<th>Median</th>
			<th>Mean</th>
			<th>Max</th>
			
			<th>Min</th>
			<th>Median</th>
			<th>Mean</th>
			<th>Max</th>
			
			<th>Min</th>
			<th>Median</th>
			<th>Mean</th>
			<th>Max</th>
		</tr>
		</thead>
		<tbody>
		<tr>
			<td><span id="token"></span></td>
			<td><span id="status">N/A</span></td>
			<td><span id="current_connections"></span></td>
			<td><span id="max_connections"></span></td>
			<td><span id="total_connections"></span></td>
			<td><span id="failed_connections"></span></td>
			
			<td><span id="open_min"></span></td>
			<td><span id="open_med"></span></td>
			<td><span id="open_avg"></span></td>
			<td><span id="open_max"></span></td>
			
			<td><span id="msg_min"></span></td>
			<td><span id="msg_med"></span></td>
			<td><span id="msg_avg"></span></td>
			<td><span id="msg_max"></span></td>
			
			<td><span id="close_min"></span></td>
			<td><span id="close_med"></span></td>
			<td><span id="close_avg"></span></td>
			<td><span id="close_max"></span></td>
		</tr>
		</tbody>
	</table>
	<table>
		<thead>
			<tr>
				<th>ID</th>
				<th>Status</th>
				<th>Start</th>
				<th>TCP</th>
				<th>Open/Fail</th>
				<th>Close sent</th>
				<th>Closed</th>
			</tr>
		</thead>
		<tbody id="results-body">
			
		</tbody>
	</table>
</div>

</body>
</html>